package com.dwy2002.user.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.dwy2002.common.Result;
import com.dwy2002.common.exception.EmptyIdException;
import com.dwy2002.common.utils.*;
import com.dwy2002.enums.Status;
import com.dwy2002.pojo.bo.TaskToUserMessageBO;
import com.dwy2002.pojo.bo.UserToTaskMessageBO;
import com.dwy2002.pojo.dto.users.PasswordLoginDTO;
import com.dwy2002.pojo.dto.users.RegisterDTO;
import com.dwy2002.pojo.dto.users.UpdateNicknameDTO;
import com.dwy2002.pojo.dto.users.UpdatePasswordDTO;
import com.dwy2002.pojo.po.users.RoleUser;
import com.dwy2002.pojo.po.users.Users;
import com.dwy2002.pojo.vo.users.UserVO;
import com.dwy2002.pojo.vo.users.UserinfoVO;
import com.dwy2002.user.mapper.UsersMapper;
import com.dwy2002.user.service.IRoleService;
import com.dwy2002.user.service.IUsersService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Objects;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.OssUtils.isFileOver;
import static com.dwy2002.common.utils.PhoneValidator.validatePhoneNumber;
import static com.dwy2002.common.utils.Utils.*;
import static com.dwy2002.enums.OssEnum.DEFAULT_AVATAR_URL;
import static com.dwy2002.enums.rabbit.TaskRabbitConstants.TASK_TO_USER_REQUEST_QUEUE;
import static com.dwy2002.enums.rabbit.TaskRabbitConstants.USER_TO_TASK_RESPONSE_QUEUE;

/**
 * @author 杜伟毅
 * @version 2.0
 * @since 2025/01/10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {
    private final JwtUtil jwtUtil;
    private final IRoleService roleService;
    private final OssUtils ossUtils;
    private final RabbitTemplate rabbitTemplate;

    /**
     * 登录
     *
     * @param userinfo 登录信息
     * @author 杜伟毅
     * @since 2024/1/11 0002 14:19
     */
    @Override
    public Result<String> login(PasswordLoginDTO userinfo) {
        if (!isPhoneNumberExist(userinfo.getPhone())) {
            return fail(Status.BAD_REQUEST, "手机号未注册，请前往注册");
        }
        Validator.of(userinfo)
                .notEmpty(PasswordLoginDTO::getPhone, "手机号为空，登陆失败")
                .notEmpty(PasswordLoginDTO::getPassword, "密码为空，登陆失败")
                .validate();
        LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
        lqw.eq(userinfo.getPhone() != null, Users::getPhone, userinfo.getPhone());
        Users users = getOne(lqw);

        //验证密码
        if (!HashUtils.verifyPassword(userinfo.getPassword(), users.getPassword())) {
            return fail(Status.BAD_REQUEST, "密码错误，请重新输入");
        }
        if (users.getIsLocked() == 1) {
            return fail(Status.BAD_REQUEST, "不好意思，您已被封禁，请联系管理员");
        }
        //生成并返回token给前端
        UserVO userVO = BeanUtil.copyProperties(users, UserVO.class);
        userVO.setRole(roleService.getUserRole(users.getId()));
        String token = jwtUtil.createToken(userVO);
        return success(token);
    }

    /**
     * 注册
     *
     * @param userinfo 注册信息
     * @author 杜伟毅
     * @since 2024/1/11 0002 14:19
     */
    @Override
    public Result<Void> register(RegisterDTO userinfo) {
        Validator.of(userinfo)
                .notEmpty(RegisterDTO::getPhone, "手机号为空，登陆失败")
                .notEmpty(RegisterDTO::getPassword, "密码为空，登陆失败")
                .mustSatisfy(!validatePhoneNumber(userinfo.getPhone()), "手机号格式错误")
                .mustSatisfy(isPhoneNumberExist(userinfo.getPhone()), "手机号已被注册")
                .mustSatisfy(!isPhoneNumberExist(userinfo.getRecommendedByPhone()), "推荐人手机号未注册，找不到该号码")
                .validate();

//        if (!Validator.validatePassword(userinfo.getPhone())) {return fail(Status.BAD_REQUEST,"密码格式错误");}

        //对密码进行hash加密
        String userId = IdWorker.get32UUID();
        userinfo.setId(userId);
        userinfo.setPassword(HashUtils.generateHash(userinfo.getPassword()));
        userinfo.setRecommendedByPhone(userinfo.getRecommendedByPhone());
        Users user = BeanUtil.copyProperties(userinfo, Users.class);
        user.setNickname(NicknameGeneratorUtils.generatorNickname(userinfo.getPhone()));
        //默认头像
        user.setAvatar(DEFAULT_AVATAR_URL.getUrl());
        boolean save = save(user);

        RoleUser roleUser = new RoleUser();
        if (isEmptyOrNull(userinfo.getRoleId())) {
            //如果为空，自动注册为顾客
            roleUser.setRoleId("d39bfb53b5e9352714b3f4288ab4ae5f");
        } else {
            //反之则是指定的角色
            roleUser.setRoleId(userinfo.getRoleId());
        }
        roleUser.setUserId(userId);
        Db.save(roleUser);

        return saveResult(save, "注册成功，欢迎来到云水茗约！", "注册失败");
    }

    /**
     * 获取用户信息
     *
     * @author 杜伟毅
     * @since 2024/1/11 21:11
     */
    @Override
    public Result<UserinfoVO> getUserInfo() {
        String token = getToken();
        if (isEmptyOrNull(token)) return fail(Status.UNAUTHORIZED, "token为空，请重新登录");

        String userId = jwtUtil.parseToken(token, Users.class).getId();
        UserinfoVO userinfoVO = BeanUtil.copyProperties(getById(userId), UserinfoVO.class);
        userinfoVO.setRoleName(roleService.getUserRole(userId).getRoleName());
        return success(userinfoVO);
    }

    /**
     * 修改密码
     *
     * @param dto 修改密码类
     * @author 杜伟毅
     * @since 2025/1/12 0012 16:06
     */
    @Override
    public Result<Void> updatePassword(UpdatePasswordDTO dto) {
        Validator.of(dto)
                .notEmpty(UpdatePasswordDTO::getPhone, "手机号为空")
                .notEmpty(UpdatePasswordDTO::getOldPassword, "旧密码为空")
                .notEmpty(UpdatePasswordDTO::getNewPassword, "新密码为空,请输入您的新密码")
                .validate();
        LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Users::getPhone, dto.getPhone());
        Users user = getOne(lqw);

        /*
        验证传过来的手机号是否与token里登录的一致
         */
        //获取token
        String token = getToken();
        if (isEmptyOrNull(token)) {
            return fail(Status.UNAUTHORIZED, "token为空，请重新登录");
        }
        Users jwtUser = jwtUtil.parseToken(token, Users.class);
        if (!jwtUser.getPhone().equals(dto.getPhone())) {
            return fail(Status.BAD_REQUEST, "您要修改的账号与当前登录的账号不同，请输入当前登陆的账号。");
        }

        //验证旧密码是否与数据库中的一致
        if (!HashUtils.verifyPassword(dto.getOldPassword(), user.getPassword())) {
            return fail(Status.BAD_REQUEST, "不好意思，您输入的密码不正确，请重新输入");
        }

        /*
         验证码逻辑，过段时间添加
         */
        user.setPassword(HashUtils.generateHash(dto.getNewPassword()));
        boolean update = updateById(user);

        return handleResult(update, "密码修改成功", "密码修改失败");
    }

    /**
     * 修改昵称
     *
     * @param userinfo 用户的修改信息
     * @author 杜伟毅
     * @since 2025/1/18 0018 16:36
     */
    @Override
    public Result<Void> updateNickname(UpdateNicknameDTO userinfo) {
        if (isEmptyOrNull(userinfo.getNewNickname())) {
            return fail(Status.BAD_REQUEST, "修改后的昵称不允许为空");
        }
        //获取当前登陆的手机号
        String phone = jwtUtil.parseToken(getToken(), Users.class).getPhone();
        LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Users::getPhone, phone);
        Users user = getOne(lqw);
        //判断新昵称是否与数据库中的昵称相同，相同则直接返回，
        if (Objects.equals(user.getNickname(), userinfo.getNewNickname())) {
            return noContent("昵称修改成功");
        }
        LambdaUpdateWrapper<Users> luw = new LambdaUpdateWrapper<>();
        luw.eq(Users::getPhone, phone).set(Users::getNickname, userinfo.getNewNickname());
        boolean update = update(null, luw);

        return handleResult(update, "昵称修改成功", "昵称修改失败");
    }

    /**
     * 修改头像
     *
     * @param oldAvatar 旧头像的地址
     * @param newAvatar 新头像的文件
     * @author 杜伟毅
     * @since 2025/1/19 0019 12:43
     */
    @Override
    public Result<Void> updateAvatar(String oldAvatar, MultipartFile newAvatar) throws IOException {
        if (isEmptyOrNull(oldAvatar) || isFileEmpty(newAvatar)) {
            //因为是前端隐性传入，不许要返回提示
            log.error("oldAvatar:------>{}", oldAvatar);
            return fail(Status.BAD_REQUEST, "新头像不能为空");
        }
        if (isFileOver(newAvatar.getSize(), 5)) {
            return fail(Status.BAD_REQUEST, "图片超出范围，请上传小于5MB的图片");
        }
        LambdaUpdateWrapper<Users> luw = new LambdaUpdateWrapper<>();
        String token = getToken();
        String phone = jwtUtil.parseToken(token, Users.class).getPhone();
        luw.eq(!isEmptyOrNull(phone), Users::getPhone, phone)
                .set(Users::getAvatar, ossUtils.uploadAvatar(newAvatar));
        boolean update = update(luw);

        //删除旧的头像
        ossUtils.deleteImage(oldAvatar);

        return handleResult(update, "头像修改成功", "头像修改失败");
    }

    /**
     * 校验手机号是否存在
     *
     * @param phone 手机号
     * @return true：手机号存在 false：手机号不存在
     * @author 杜伟毅
     * @since 2024/1/11 0012 15:06
     */
    @Override
    public boolean isPhoneNumberExist(String phone) {
        LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
        lqw.eq(!isEmptyOrNull(phone), Users::getPhone, phone);
        return exists(lqw);
    }

    /**
     * 获取昵称
     *
     * @param id 用户id
     * @return 返回对应的昵称
     * @author 杜伟毅
     * @since 2025/7/15 0015 16:33
     */
    @Override
    public String getNickname(String id) {
        if (isEmptyOrNull(id)) throw new EmptyIdException("getNickname");
        return getById(id).getNickname();
    }

    // 子方法：-----------------------------------------------------------------

    /**
     * @author 杜伟毅
     * @since 2025/3/24 0024 21:10
     */
    @RabbitListener(queues = TASK_TO_USER_REQUEST_QUEUE)
    public void handleTaskRequest(TaskToUserMessageBO bo) {

        String assigneeNickname = getNickname(bo.getAssigneeId());
        String creatorNickname = getNickname(bo.getCreatorId());

        UserToTaskMessageBO userToTaskMessageBO = new UserToTaskMessageBO()
                .setAssigneeNickname(assigneeNickname)
                .setCreatorNickname(creatorNickname);

        // 发送响应到ReplyTo队列
        rabbitTemplate.convertAndSend(USER_TO_TASK_RESPONSE_QUEUE, userToTaskMessageBO);
    }
}
/*
2.0优化：
修改原先大段的重复的if-return格式的代码，采用 "校验链 + 统一异常处理" 模式，结合策略模式与函数式编程思想，实现以下优化：
1.校验逻辑集中管理
2.错误信息统一收集
3.代码行数减少50%以上
4.支持单次返回多个错误
 */